# coding:utf-8
import datetime
import os
from docxtpl import DocxTemplate
import jinja2
import getopt
import sys
from pprint import pprint
import pandas as pd
import time
from decimal import Decimal

# 过滤器对字段进行处理,由于部分字段格式需求在读取表格时是无法预测的，所以无法提前处理，
# 可以采用过滤器的形势进一步在模板中处理
def filter_date(value):  # 返回日期格式  2022-10-02

    # value 类型需要自己判断，根据类型进行处理
    try:
        return value.date()
    except Exception as e:
        print("{}  日期过滤器处理异常，将不进行处理".format(value))
        print(e)
        return value


# 将时间格式的字段，返回为 日期 时间格式   2022-10-02 10:11:00 这样的格式
def filter_datetime(value):
    try:
        return "{} {}".format(value.date(), value.time())
    except Exception as e:
        print("{}  日期时间过滤器处理异常，将不进行处理".format(value))
        print(e)
        return value


# 将时间格式的字段，返回为 日期 时间格式  10:11:00 这样的格式
def filter_time(value):
    try:
        return value.time()
    except Exception as e:
        print("{}  时间过滤器处理异常，将不进行处理".format(value))
        print(e)
        return value


def my_round(value, v=2):
    try:
        return Decimal(float(value)).quantize(Decimal("0."+"0"*v))
    except Exception as e:
        print("{}  保留小数处理异常，将不进行处理".format(value))
        print(e)
        return value


jinja_env = jinja2.Environment()
jinja_env.filters['date'] = filter_date  # 注册过滤器 ，date 是模板里调用的名称
jinja_env.filters['datetime'] = filter_datetime
jinja_env.filters['time'] = filter_time
jinja_env.filters['my_round'] = my_round


class MainClass(object):
    def __init__(self, execl_path, word_template, out_path):
        # 输出文件夹创建
        os.makedirs(out_path, exist_ok=True)
        self.execl_path = execl_path
        self.word_template = word_template
        self.out_path = out_path
        self.isfile()
        self.context = {}
        self.data = []

    def isfile(self):
        if not os.access(execl_path, os.R_OK):
            print("execl 无法访问 {}".format(execl_path))
            sys.exit(0)
        if not os.access(word_template, os.R_OK):
            print("word 无法访问 {}".format(execl_path))
            sys.exit(0)

    # 执行
    def run(self):
        self.read_execl()  # 读取execl 表内容
        if self.data:
            d = self.data[0]
            print("表格中存在的标题字段: \n\t{}".format(sorted(set(d.keys()))))
        else:
            print("表格内容为空")
            sys.exit(0)
        # 读取模板
        doc = DocxTemplate(self.word_template)
        # 获取模板变量
        template_variables = list(doc.get_undeclared_template_variables(jinja_env))
        print("模板中需要替换的字段：\n\t{}\n".format(sorted(template_variables)))
        i = 1
        for d in self.data:
            # 提取表名
            table_name_key = self.get_table_name(template_variables)
            if table_name_key in template_variables:
                template_variables.remove(table_name_key)
            table_name = table_name_key.split("__tableName__")[-1]

            # 判断word 里面的字段是否都存在execl中，如果有不存在的则提示
            if not set(template_variables).issubset(set(d.keys())):
                print('\033[1;31m')
                print("第 {} 行:".format(i))
                s = ""
                for t_var in template_variables:
                    if t_var not in list(d.keys()):
                        s += t_var + "，"
                print("字段 {} 不存在表格中".format(s))
                print("可能替换不完全，请检查, 请检查文档是否正确...... ")
                print(" * " * 20)
                print('\033[0m')

            # 保存word
            if not table_name:
                table_name = str(int(time.time()))
                print("\033[1;31m 未读取到表名，将采用时间戳命名\033[0m")
                self.save_doc(d, table_name)
            else:
                self.save_doc(d, d.get(table_name))
            template_variables.append(table_name_key)
            i += 1

    def get_table_name(self, d):
        for i in d:
            if i.startswith("__tableName__"):
                return i
        return None  # 避免没有表名，这里用时间戳，代替

    # 保存
    def save_doc(self, context, p):
        pprint(context)
        doc = DocxTemplate(self.word_template)
        doc.render(context, jinja_env)
        path = os.path.join(self.out_path, str(p))
        doc.save("{}.docx".format(path))

    def read_execl(self):
        try:
            self.data = []

            df = pd.read_excel(self.execl_path, dtype=dtype)  # type: pd.DataFrame

            # 将nan 替换成 ""
            df = df.fillna("")
            df.apply(self.to_dict, axis=1)  # 将execl 里每一行数据转换为字典，添加到列表
        except Exception as e:
            print("execl 读取错误", e)

    def to_dict(self, d):
        self.data.append(d.to_dict())


if __name__ == "__main__":
    # execl路径
    execl_path = "execl_template.xlsx"
    # word模板路径
    word_template = "word_template.docx"
    # 生成文件保存的路径
    out_path = "./"

    # 指定execl 表里某一列的数据类型
    dtype = {
        "邮编": str,
        "number": int,
        "温度": float,

    }

    try:
        opts, args = getopt.getopt(sys.argv[1:], "", ["execl_path=", "word_template=", "out_path="])
        key_set = {"--execl_path", "--out_path", "--word_template"}
        if opts:
            param = dict(opts)
            execl_path = param.get("--execl_path")
            out_path = param.get("--out_path")
            word_template = param.get("--word_template")
        print("execl表格路径：{}\nword模板路径：{}\n文件输出路径：{}\n".format(execl_path, word_template, out_path))
        main = MainClass(execl_path, word_template, out_path)
        main.run()
    except getopt.GetoptError as e:
        print("参数错误: \n \t运行方式:  python main.py --execl_path xxx  --word_template xxx --out_path xxx")
        print("--execl_path 输入execl 表的路径\n"
              "--word_template word 模板的路径\n"
              "--out_path 输出文件保存路径\n")
